﻿
namespace Patterns4Net.Tests.Core.CecilExtensions 
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.Contracts;
    using System.Linq;
    using Mono.Cecil;
    using NUnit.Framework;
    using Patterns4Net.Core.CecilExtensions;

    [TestFixture]
    public class CecilToReflectionTest 
    {
        /// <summary>
        /// This test assumes that ReflectionToCecil extensions work properly.
        /// </summary>
        [Test]
        [Category("Integration")]
        public void Try_To_Load_This_Module_Get_TypeDefinition_Of_This_Class_And_Get_SystemType_Of_It() 
        {
            ModuleDefinition module = this.GetType().Assembly.GetModuleDefinition();
            Contract.Assume(module != null);
            Contract.Assume(module.Types != null);
            TypeDefinition thisTypeDefinition = module.Types.Where(x => x.FullName == this.GetType().FullName).FirstOrDefault();
            Contract.Assume(thisTypeDefinition != null);
            Type type = thisTypeDefinition.GetSystemType();

            Assert.AreEqual(this.GetType(), type);
        }

        [Test]
        public void IsEqual_With_Equal_FullNames_Returns_True()
        {
            var thisType = this.GetType();
            var typeReference = new TypeReference(thisType.Namespace, thisType.Name, null, null);
            Assert.IsTrue(typeReference.IsEqual(thisType));
        }

        [Test]
        public void IsEqual_With_Equal_Nested_FullNames_Returns_True()
        {
            var nestedType = typeof(Nested);
            var thisType = this.GetType();
            var thisReference = new TypeReference(thisType.Namespace, thisType.Name, null, null);
            var nestedReference = new TypeReference(string.Empty, nestedType.Name, null, null);
            nestedReference.DeclaringType = thisReference;

            Assert.IsTrue(nestedReference.IsEqual(nestedType));            
        }

        [Test]
        public void IsEqual_With_Unequal_FullNames_Returns_False()
        {
            var thisType = this.GetType();
            var typeReference = new TypeReference("Hello.World", thisType.Name, null, null);
            Assert.IsFalse(typeReference.IsEqual(thisType));            
        }

        [Test]
        public void IsEqual_With_IEnumerables_Of_Int_Returns_True()
        {
            var thisType = typeof(IEnumerable<int>);
            var typeReference = typeof(IEnumerable<int>).GetTypeReference();
            Assert.IsTrue(typeReference.IsEqual(thisType));            
        }

        [Test]
        public void IsEqual_With_IEnumerables_Of_Int_And_List_Of_Int_Returns_False()
        {
            var thisType = typeof(IEnumerable<int>);
            var typeReference = typeof(List<int>).GetTypeReference();
            Assert.IsFalse(typeReference.IsEqual(thisType));            
        }

        [Test]
        public void GetReflectionTypeName_Converts_Slash_To_Plus()
        {
            var name = CecilToReflection.GetReflectionTypeName("Hello.World/Nested");
            Assert.AreEqual("Hello.World+Nested", name);
        }

        /// <summary>
        /// Nested dummy class.
        /// </summary>
        public class Nested
        {            
        }
    }
}